// --------------------------------------------------------------------------------------------------------------------
// <copyright file="GamePadUnitTests.cs" company="Microsoft Corporation">
// The MIT License (MIT)
// 
// Copyright (c) 2014, Microsoft Corporation
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
namespace Microsoft.Robotics.Interaction.Runtime.UnitTests
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Reflection;
    using System.Threading;
    using Microsoft.Robotics.Interaction.Runtime.Input;
    using Microsoft.Robotics.Interaction.Xna;
    using Microsoft.Robotics.IO;
    using Microsoft.Robotics.Runtime;
    using Microsoft.Robotics.Visualization;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Input;
    using Test.Robotics.Interaction;
    using Test.Robotics.Runtime; 
    
    /// <summary>
    /// Basic unit test XNA Input (Game Pad) testing
    /// </summary>
    [TestClass]
    public class GamePadAgentUnitTests
    {
        /// <summary>
        /// Start the Game Pad Agent pipeline and ensure you get game pad messages back.
        /// </summary>
        [Priority(0)]
        [TestMethod]
        [TestCategory("Unit")]
        public void GamePadPipelineTest()
        {
            Manifest manifest = new Manifest();
            List<ViewDefinition> views = new List<ViewDefinition>();

            // add the agents 
            GamePadAgent gamePadAgent = InteractionManifest.AddGamePadAgent(manifest, views);

            manifest.Agents.Add(gamePadAgent);

            MessageCollectorAgent<GamePadAgentMessage> collector =
                new MessageCollectorAgent<GamePadAgentMessage>("collector", gamePadAgent);
            manifest.Agents.Add(collector);

            manifest.ActiveAgents.Add(gamePadAgent.Name);
            manifest.ActiveAgents.Add(collector.Name);

            AgentLocator locator = new AgentLocator();
            locator.LoadFrom(manifest);

            // Wait for the message to appear at end of pipeline
            collector.Wait(30000);

            locator.Deactivate();

            Assert.IsTrue(
                collector.Results.Count >= 1,
                string.Format("No game pad messages were collected."));
        }

        /// <summary>
        /// Test the implicit conversion between GamePadMessage and XNA GamePadState.
        /// </summary>
        [Priority(0)]
        [TestMethod]
        [TestCategory("Unit")]
        public void GamePadStateConversionTest()
        {
            // run twice to test both sides of conditionals
            this.RunConversionTest(true);
            this.RunConversionTest(false);
        }

        /// <summary>
        /// Tests implicit conversion between GamePadMessage and XNA GamePadState
        /// </summary>
        /// <param name="initialBool">An initial boolean value</param>
        private void RunConversionTest(bool initialBool)
        {
            GamePadAgentMessage message = new GamePadAgentMessage();
            message.Buttons = new GamePadAgentMessage.GamePadAgentButtons();
            message.Buttons.A = initialBool;
            message.Buttons.B = !initialBool;
            message.Buttons.Back = initialBool;
            message.Buttons.BigButton = !initialBool;
            message.Buttons.LeftShoulder = initialBool;
            message.Buttons.LeftStick = !initialBool;
            message.Buttons.RightShoulder = initialBool;
            message.Buttons.RightStick = !initialBool;
            message.Buttons.Start = initialBool;
            message.Buttons.X = !initialBool;
            message.Buttons.Y = initialBool;

            message.DPad = new GamePadAgentMessage.GamePadAgentDPad();
            message.DPad.Down = initialBool;
            message.DPad.Left = !initialBool;
            message.DPad.Right = initialBool;
            message.DPad.Up = !initialBool;

            message.ThumbSticks = new GamePadAgentMessage.GamePadAgentThumbSticks();
            message.ThumbSticks.Left = new GamePadAgentMessage.GamePadAgentVector2();
            message.ThumbSticks.Left.X = .9f;
            message.ThumbSticks.Left.Y = -.1f;
            message.ThumbSticks.Right = new GamePadAgentMessage.GamePadAgentVector2();
            message.ThumbSticks.Right.X = .9f;
            message.ThumbSticks.Right.Y = -.1f;

            message.Triggers = new GamePadAgentMessage.GamePadAgentTriggers();
            message.Triggers.Left = .9f;
            message.Triggers.Right = .1f;

            // Test conversion to state
            GamePadState state = message.ToGamePadState();

            ButtonState buttonState1 = initialBool ? ButtonState.Pressed : ButtonState.Released;
            ButtonState buttonState2 = initialBool ? ButtonState.Released : ButtonState.Pressed;

            Assert.AreEqual(buttonState1, state.Buttons.A);
            Assert.AreEqual(buttonState2, state.Buttons.B);
            Assert.AreEqual(buttonState1, state.Buttons.Back);
            Assert.AreEqual(buttonState2, state.Buttons.BigButton);
            Assert.AreEqual(buttonState1, state.Buttons.LeftShoulder);
            Assert.AreEqual(buttonState2, state.Buttons.LeftStick);
            Assert.AreEqual(buttonState1, state.Buttons.RightShoulder);
            Assert.AreEqual(buttonState2, state.Buttons.RightStick);
            Assert.AreEqual(buttonState1, state.Buttons.Start);
            Assert.AreEqual(buttonState2, state.Buttons.X);
            Assert.AreEqual(buttonState1, state.Buttons.Y);

            Assert.AreEqual(buttonState1, state.DPad.Down);
            Assert.AreEqual(buttonState2, state.DPad.Left);
            Assert.AreEqual(buttonState1, state.DPad.Right);
            Assert.AreEqual(buttonState2, state.DPad.Up);

            Assert.AreEqual(message.ThumbSticks.Left.X, state.ThumbSticks.Left.X);
            Assert.AreEqual(message.ThumbSticks.Left.Y, state.ThumbSticks.Left.Y);
            Assert.AreEqual(message.ThumbSticks.Right.X, state.ThumbSticks.Right.X);
            Assert.AreEqual(message.ThumbSticks.Right.Y, state.ThumbSticks.Right.Y);

            Assert.AreEqual(message.Triggers.Left, state.Triggers.Left);
            Assert.AreEqual(message.Triggers.Right, state.Triggers.Right);

            // Test conversion to message
            GamePadAgentMessage message2 = state.ToGamePadAgentMessage();

            Assert.AreEqual(initialBool, message.Buttons.A);
            Assert.AreEqual(!initialBool, message.Buttons.B);
            Assert.AreEqual(initialBool, message.Buttons.Back);
            Assert.AreEqual(!initialBool, message.Buttons.BigButton);
            Assert.AreEqual(initialBool, message.Buttons.LeftShoulder);
            Assert.AreEqual(!initialBool, message.Buttons.LeftStick);
            Assert.AreEqual(initialBool, message.Buttons.RightShoulder);
            Assert.AreEqual(!initialBool, message.Buttons.RightStick);
            Assert.AreEqual(initialBool, message.Buttons.Start);
            Assert.AreEqual(!initialBool, message.Buttons.X);
            Assert.AreEqual(initialBool, message.Buttons.Y);

            Assert.AreEqual(initialBool, message.DPad.Down);
            Assert.AreEqual(!initialBool, message.DPad.Left);
            Assert.AreEqual(initialBool, message.DPad.Right);
            Assert.AreEqual(!initialBool, message.DPad.Up);

            Assert.AreEqual(message.ThumbSticks.Left.X, state.ThumbSticks.Left.X);
            Assert.AreEqual(message.ThumbSticks.Left.Y, state.ThumbSticks.Left.Y);
            Assert.AreEqual(message.ThumbSticks.Right.X, state.ThumbSticks.Right.X);
            Assert.AreEqual(message.ThumbSticks.Right.Y, state.ThumbSticks.Right.Y);

            Assert.AreEqual(message.Triggers.Left, state.Triggers.Left);
            Assert.AreEqual(message.Triggers.Right, state.Triggers.Right);
        }
    }
}
